from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from classdata import *
import json
import pathlib
import logging
import time
import socket
import os
import pymysql
import sqlite3
import loger
import random
log = loger.Logger('2-class',StreamLevel='debug',FileLevel='info').logger
# chrome.exe --remote-debugging-port=9222 --user-data-dir=D:\selenium_chrome
# https://bot.sannysoft.com/
root=pathlib.Path(__file__).parent
browser=None
sqlType="mysql" #sqlite
CorrectRate=0.85
waittime=15
db=None
cur=None
userinfo=None
def init():
    global browser
    chrome_options = Options()
    chrome_options.add_experimental_option("debuggerAddress", "127.0.0.1:9222")
    service=Service(str(root/"chromedriver.exe"))
    browser = webdriver.Chrome(service=service, options=chrome_options)
    # browser = webdriver.Chrome(options=chrome_options)
    browser.maximize_window()
    return browser
# /html/body/div[5]/table/tbody/tr[2]/td[2]/div[3]/button
def initdb():
    global db
    global cur
    if (sqlType=="mysql"):
        hostnamelist = ['192.168.2.247',"172.16.2.174","192.168.8.247"] #example
        for i in hostnamelist:
            response = os.system(f"ping -n 1 -w 500 {i}" )
            if response == 0:
                print(f"connect {i}")
                try:
                    db = pymysql.connect(
                        host=i
                        ,user='xjzx'
                        ,password='Af1121113'
                        ,db='2class'
                        ,charset='utf8')
                except:
                    print(f"mysql {i} connect error!")
                    exit()
                break
            else:
                print (i, 'is down!')
    elif(sqlType=="sqlite"):
        db=sqlite3.connect(str(root/"2_class.db"))

    cur = db.cursor()
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.connect(("8.8.8.8", 80))
    ipaddr=(s.getsockname()[0])
    print(ipaddr)

def findxpath(xpath,t=3):
    global browser
    browser.implicitly_wait(t)
    try:
        result = browser.find_element(By.XPATH,xpath)
    except :
        log.info(f"not find xpath:\t{xpath}")
        result= None

    return result

def findlinktext(text,t=5):
    global browser
    browser.implicitly_wait(t)
    try:
        result = browser.find_element(By.LINK_TEXT,text)
    except :
        log.info("not find xpath!")
        result= None
    return result

def clickobj(obj):
    global browser
    actions = ActionChains(browser)
    actions.move_to_element(obj)
    actions.click(obj)
    actions.perform()
def login(username=None,password=None):
    global userinfo
    resute = browser.execute_script('return window.__DATA__.userInfo.account;')
    if resute== None:
        obj=findlinktext("登录")
        clickobj(obj)
        time.sleep(5)
        account=findxpath('/html/body/div[2]/div/div[2]/div/div[1]/div/form/div/div/div/div[1]/div/div/input')
        pwd=findxpath('/html/body/div[2]/div/div[2]/div/div[1]/div/form/div/div/div/div[2]/div/div/input')
        if(username==None):
            r=get_db("SELECT * FROM class_userinfo  where classhour is null LIMIT 0, 1")
            r=None if(len(r)==0) else r[0]
            userinfo=r
            username=userinfo[3]
            password=userinfo[4]
        account.send_keys(username)
        pwd.send_keys(password)
        trysql(f"UPDATE class_userinfo SET classhour=-1 WHERE (`账号`='{userinfo[3]}')")
        time.sleep(3)
        obj=findxpath("/html/body/div[2]/div/div[2]/div/div[1]/div/form/div/div/div/button")
        clickobj(obj)
        time.sleep(3)
        obj=findxpath("/html/body/div[2]/div/div[2]/div/div[1]/div/form/div/div/div/div[4]/div/div/div/div/span") #验证滑块
        if(obj!=None):
            ActionChains(browser).click_and_hold(obj).perform()
            time.sleep(1)
            ActionChains(browser).move_by_offset(360, 0).perform()
            ActionChains(browser).release(obj).perform()
            time.sleep(3)
        r=waitXpath(["//span[text()='我的课程']","//span[text()='我的课程']"])
        if(r[0]==None):
            trysql(f"UPDATE class_userinfo SET classhour = NULL WHERE (`账号`='{userinfo[3]}')")
            log.info(f"登录失败3 {userinfo[3]}")
            return False
        else:
            log.info(f"{userinfo[5]}{userinfo[2]}\t{userinfo[1]}\t{userinfo[3]}登录成功")
            return True
    else:
        r=get_db(f"SELECT * FROM class_userinfo  where `账号` = '{resute}'")
        userinfo=r[0]
        log.info(f"{userinfo[5]}{userinfo[2]}\t{userinfo[1]}\t{userinfo[3]}已登录")
    
def getjson(url):
    global browser
    browser.get(url)
    browser.implicitly_wait(waittime)
    time.sleep(0.5)
    t=browser.page_source
    t=t.replace("<html><head></head><body>","")
    t=t.replace("</body></html>","")
    t=json.loads(t)
    # t=demjson.decode(t)
    return t
def get_db(sql):
    cur.execute(sql)
    if (sqlType=="mysql"):
        return cur.fetchall()
    elif(sqlType=="sqlite"):
        r=cur.execute(sql)
        return r.fetchall()
def logout():
    try:
        json=getclasshours() 
        log.info(f"{userinfo[5]}{userinfo[2]}\t{userinfo[1]}\t完成{json['data']['classHour']}课时")
    except Exception as e:
        log.error(f"分数记录异常！{e}")
    browser.get("https://www.2-class.com")
    browser.implicitly_wait(waittime)
    time.sleep(2)

    try:
        titlec=findxpath("/html/body/div/div/div[1]/div/header/div/div[2]/div[2]/div/a")
        ActionChains(browser).move_to_element(titlec).perform()
        time.sleep(1.5)
        clickobj(findxpath("/html/body/div/div/div[1]/div/header/div/div[2]/div[2]/div/div/ul/li[6]"))
    except Exception as e:
        log.error(f"退出异常 {e}")
        openurl("https://www.2-class.com/api/user/logout",waitmax=1,waitmin=0)

def trysql(sql):
        try:
            cur.execute(sql)
            db.commit()
        except Exception as e:
            log.error(f"数据库异常 :{e}")
def getclasshours():
    json=getjson("https://www.2-class.com/api/growth/getMyBank")
    if(json['data']==None):
        sql=f"UPDATE class_userinfo SET classhour=-4 WHERE (id={userinfo[0]})"
    else:
        sql=f"UPDATE class_userinfo SET classhour={json['data']['classHour']} WHERE (id={userinfo[0]})"
    trysql(sql)
    return json
def classhours(ids):
    for i in ids:
        t=random.random()
        if(t<=0.8):
            log.info(f"开始练习{i}")
            try:
                if(findlinktext("登录") != None):
                    continue
                doExercises(i)
            except:
                log.info(f"练习{i}没有完成")
                log.error(f"练习{i}没有完成")
            time.sleep(3)

        else:
            log.info(f"练习{i}跳过")
def doExercises(id):
    openurl(f"https://www.2-class.com/courses/exams/{id}",3,1)
    r=waitXpath(["//span[text()='开始答题']","//span[text()='知道了']"])
    if(r[1]==-1):
        log.error("连续打开错误！")
        return False
    elif(r[1]==1):
        log.info(f"练习{id}已经完成")
        return True
    else:
        log.info(f"开始练习{id}")
        clickobj(findxpath("/html/body/div/div/div[1]/div/div/div/div[1]/div/button/span"))
        time.sleep(1)
        answer=coursesExamsAnswer[id]

        xpaths=[     "/html/body/div/div/div[1]/div/div/div/div[1]/div/div[2]/label[1]/span[1]/input"
                    ,"/html/body/div/div/div[1]/div/div/div/div[1]/div/div[2]/label[2]/span[1]/input"
                    ,"/html/body/div/div/div[1]/div/div/div/div[1]/div/div[2]/label[3]/span[1]/input"
                    ,"/html/body/div/div/div[1]/div/div/div/div[1]/div/div[2]/label[4]/span[1]/input"]
        for i in answer:
            if (type(i)==int):
                obj=findxpath(xpaths[i])
                clickobj(obj)
                time.sleep(0.3)
            else:
                for i1 in i :
                    obj=findxpath(xpaths[i1])
                    clickobj(obj)
                    time.sleep(0.3)
            obj=findxpath("//span[text()='下一题']")
            if(obj==None):
                obj=findxpath("//span[text()='提交']")
            if(obj==None):
                log.error("练习提交错误")
            else:
                clickobj(obj)
            time.sleep(1)
def openurl(url,waitmax=3,waitmin=1):
    browser.get(url)
    browser.implicitly_wait(waittime)
    time.sleep(random.uniform(waitmin,waitmax))

def waitXpath(xpath,times=3,waittime=15):
    while(times>0):
        n=0
        for i in xpath:
            obj=findxpath(i)
            if (obj!=None):
                return (obj,n)
                break
            n=n+1
        times=times-1
        browser.refresh()
        browser.implicitly_wait(waittime)
    return (None,-1)


if __name__ =="__main__":
    init()
    initdb()
    # obj=findxpath("//span[text()='知道了']")
    # clickobj(obj)
    while (True):
        openurl("https://www.2-class.com",5,3)

        r=get_db("SELECT * FROM class_userinfo  where classhour is null LIMIT 0, 1")
        r=None if(len(r)==0) else r[0]
        userinfo=r
        # r=cur.execute("SELECT * FROM class_userinfo  where status = '0' LIMIT 0, 1")
        # r=cur.fetchone()
        if(r==None): 
            log.info("<-----完成----->")
            break

        try:
            if(login()==False):
                continue
            # pass
        except Exception as e:
            log.error(f"{userinfo[3]}登录异常 :{e}")
            trysql(f"UPDATE class_userinfo SET classhour=-3 WHERE (`账号`='{userinfo[3]}')")
            continue
        browser.refresh()
        r=waitXpath(["//span[text()='我的课程']","//span[text()='我的课程']"])
        if(r[0]==None):
            log.error(f"{userinfo[3]}登录异常2")
            logout()
        obj=findxpath("//div[text()='查看勋章']")
        if(obj!=None):clickobj(obj)
        classhours(courseId[userinfo[5]])
        logout()
        time.sleep(5)
    
